{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "79a3f6a4-8348-4cd6-a336-10ecb9cfaaa3",
   "metadata": {},
   "source": [
    "# Conversational agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "36261434-a96c-49e8-ad41-918d14da089a",
   "metadata": {
    "height": 115,
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import openai\n",
    "\n",
    "from dotenv import load_dotenv, find_dotenv\n",
    "_ = load_dotenv(find_dotenv()) # read local .env file\n",
    "openai.api_key = os.environ['OPENAI_API_KEY']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20f44fbb-6708-4fce-bac4-55dc261e3a2d",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "from langchain.tools import tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa7406eb-334b-43d0-8110-31656a55b2fd",
   "metadata": {
    "height": 692
   },
   "outputs": [],
   "source": [
    "import requests\n",
    "from pydantic import BaseModel, Field\n",
    "import datetime\n",
    "\n",
    "# Define the input schema\n",
    "class OpenMeteoInput(BaseModel):\n",
    "    latitude: float = Field(..., description=\"Latitude of the location to fetch weather data for\")\n",
    "    longitude: float = Field(..., description=\"Longitude of the location to fetch weather data for\")\n",
    "\n",
    "@tool(args_schema=OpenMeteoInput)\n",
    "def get_current_temperature(latitude: float, longitude: float) -> dict:\n",
    "    \"\"\"Fetch current temperature for given coordinates.\"\"\"\n",
    "    \n",
    "    BASE_URL = \"https://api.open-meteo.com/v1/forecast\"\n",
    "    \n",
    "    # Parameters for the request\n",
    "    params = {\n",
    "        'latitude': latitude,\n",
    "        'longitude': longitude,\n",
    "        'hourly': 'temperature_2m',\n",
    "        'forecast_days': 1,\n",
    "    }\n",
    "\n",
    "    # Make the request\n",
    "    response = requests.get(BASE_URL, params=params)\n",
    "    \n",
    "    if response.status_code == 200:\n",
    "        results = response.json()\n",
    "    else:\n",
    "        raise Exception(f\"API Request failed with status code: {response.status_code}\")\n",
    "\n",
    "    current_utc_time = datetime.datetime.utcnow()\n",
    "    time_list = [datetime.datetime.fromisoformat(time_str.replace('Z', '+00:00')) for time_str in results['hourly']['time']]\n",
    "    temperature_list = results['hourly']['temperature_2m']\n",
    "    \n",
    "    closest_time_index = min(range(len(time_list)), key=lambda i: abs(time_list[i] - current_utc_time))\n",
    "    current_temperature = temperature_list[closest_time_index]\n",
    "    \n",
    "    return f'The current temperature is {current_temperature}°C'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ac0a1e7-567f-4775-a538-351a5ff099e8",
   "metadata": {
    "height": 352
   },
   "outputs": [],
   "source": [
    "import wikipedia\n",
    "\n",
    "@tool\n",
    "def search_wikipedia(query: str) -> str:\n",
    "    \"\"\"Run Wikipedia search and get page summaries.\"\"\"\n",
    "    page_titles = wikipedia.search(query)\n",
    "    summaries = []\n",
    "    for page_title in page_titles[: 3]:\n",
    "        try:\n",
    "            wiki_page =  wikipedia.page(title=page_title, auto_suggest=False)\n",
    "            summaries.append(f\"Page: {page_title}\\nSummary: {wiki_page.summary}\")\n",
    "        except (\n",
    "            self.wiki_client.exceptions.PageError,\n",
    "            self.wiki_client.exceptions.DisambiguationError,\n",
    "        ):\n",
    "            pass\n",
    "    if not summaries:\n",
    "        return \"No good Wikipedia Search Result was found\"\n",
    "    return \"\\n\\n\".join(summaries)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4856d233-0916-4b97-8a7c-b494d5f2b8e0",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "tools = [get_current_temperature, search_wikipedia]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cdf0d789-559b-42df-9d6d-77a0cd8888d6",
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.tools.render import format_tool_to_openai_function\n",
    "from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "933ce7cb-099c-4f43-a548-b355a5b66511",
   "metadata": {
    "height": 131
   },
   "outputs": [],
   "source": [
    "functions = [format_tool_to_openai_function(f) for f in tools]\n",
    "model = ChatOpenAI(temperature=0).bind(functions=functions)\n",
    "prompt = ChatPromptTemplate.from_messages([\n",
    "    (\"system\", \"You are helpful but sassy assistant\"),\n",
    "    (\"user\", \"{input}\"),\n",
    "])\n",
    "chain = prompt | model | OpenAIFunctionsAgentOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4281a2d8-7884-40e0-b34d-09c39eecbb7a",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "result = chain.invoke({\"input\": \"what is the weather is sf?\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b1dbc697-3e0a-4197-8ddc-2894763b4b85",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "result.tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab829b59-803f-488f-bcf3-5119c224baa0",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "result.tool_input"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "52b4d483-c498-4932-a373-bc2f4da17c7f",
   "metadata": {
    "height": 114
   },
   "outputs": [],
   "source": [
    "from langchain.prompts import MessagesPlaceholder\n",
    "prompt = ChatPromptTemplate.from_messages([\n",
    "    (\"system\", \"You are helpful but sassy assistant\"),\n",
    "    (\"user\", \"{input}\"),\n",
    "    MessagesPlaceholder(variable_name=\"agent_scratchpad\")\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "66ac6ea2-0e20-424a-ba33-6f8d627379b5",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "chain = prompt | model | OpenAIFunctionsAgentOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bada1de8-d7c4-4880-98c2-d47cc65f684d",
   "metadata": {
    "height": 80
   },
   "outputs": [],
   "source": [
    "result1 = chain.invoke({\n",
    "    \"input\": \"what is the weather is sf?\",\n",
    "    \"agent_scratchpad\": []\n",
    "})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d5f4e61-36a3-4d80-9c49-0b83cedb1592",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "result1.tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11845c11-7d41-455a-8ac0-4b8161acaf83",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "observation = get_current_temperature(result1.tool_input)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "810184c8-8495-4189-b83e-17220cf65bbe",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "observation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8c1b223d-ea2a-414c-924c-512c4c9da66a",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "type(result1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61853679-75b5-4462-8059-f1214286a9eb",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "from langchain.agents.format_scratchpad import format_to_openai_functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72ca4278-165a-4915-8ec6-09e696f29d86",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "result1.message_log"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27e079a7-d58c-41c0-8762-4e183e72a1d1",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "format_to_openai_functions([(result1, observation), ])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "09735a9e-452d-472b-a4c0-35c315e9e53f",
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "result2 = chain.invoke({\n",
    "    \"input\": \"what is the weather is sf?\", \n",
    "    \"agent_scratchpad\": format_to_openai_functions([(result1, observation)])\n",
    "})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9df61ecc-52fe-4fae-85a2-dbb61d68e2db",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "result2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9dd139f-e06a-4148-a025-ae100851c63e",
   "metadata": {
    "height": 301
   },
   "outputs": [],
   "source": [
    "from langchain.schema.agent import AgentFinish\n",
    "def run_agent(user_input):\n",
    "    intermediate_steps = []\n",
    "    while True:\n",
    "        result = chain.invoke({\n",
    "            \"input\": user_input, \n",
    "            \"agent_scratchpad\": format_to_openai_functions(intermediate_steps)\n",
    "        })\n",
    "        if isinstance(result, AgentFinish):\n",
    "            return result\n",
    "        tool = {\n",
    "            \"search_wikipedia\": search_wikipedia, \n",
    "            \"get_current_temperature\": get_current_temperature,\n",
    "        }[result.tool]\n",
    "        observation = tool.run(result.tool_input)\n",
    "        intermediate_steps.append((result, observation))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f6c1121-70a6-41ae-8c3d-41f7cfc756af",
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "from langchain.schema.runnable import RunnablePassthrough\n",
    "agent_chain = RunnablePassthrough.assign(\n",
    "    agent_scratchpad= lambda x: format_to_openai_functions(x[\"intermediate_steps\"])\n",
    ") | chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4a05df88-4ad9-4c48-a7dd-6b42db91cb33",
   "metadata": {
    "height": 267
   },
   "outputs": [],
   "source": [
    "def run_agent(user_input):\n",
    "    intermediate_steps = []\n",
    "    while True:\n",
    "        result = agent_chain.invoke({\n",
    "            \"input\": user_input, \n",
    "            \"intermediate_steps\": intermediate_steps\n",
    "        })\n",
    "        if isinstance(result, AgentFinish):\n",
    "            return result\n",
    "        tool = {\n",
    "            \"search_wikipedia\": search_wikipedia, \n",
    "            \"get_current_temperature\": get_current_temperature,\n",
    "        }[result.tool]\n",
    "        observation = tool.run(result.tool_input)\n",
    "        intermediate_steps.append((result, observation))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8bf88b6-9992-4041-8344-ef4921bf3cf2",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "run_agent(\"what is the weather is sf?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4c94a493-b480-409a-968a-038c8895709c",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "run_agent(\"what is langchain?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c8c6fd7-7c8c-487a-81de-1dcff739a2f9",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "run_agent(\"hi!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b270a064-8cf1-44da-a59e-be622f9099b9",
   "metadata": {
    "height": 63
   },
   "outputs": [],
   "source": [
    "from langchain.agents import AgentExecutor\n",
    "agent_executor = AgentExecutor(agent=agent_chain, tools=tools, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "87baebf4-2555-4e98-aece-a1c327644817",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "agent_executor.invoke({\"input\": \"what is langchain?\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c2da813c-47c3-487e-8c43-444c9b4d9821",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "agent_executor.invoke({\"input\": \"my name is bob\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15ba8a9f-fcb2-44d0-878f-3017f607e955",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "agent_executor.invoke({\"input\": \"what is my name\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7d1df28a-27da-4f8e-ab03-a37a276db74f",
   "metadata": {
    "height": 114
   },
   "outputs": [],
   "source": [
    "prompt = ChatPromptTemplate.from_messages([\n",
    "    (\"system\", \"You are helpful but sassy assistant\"),\n",
    "    MessagesPlaceholder(variable_name=\"chat_history\"),\n",
    "    (\"user\", \"{input}\"),\n",
    "    MessagesPlaceholder(variable_name=\"agent_scratchpad\")\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a8598e87-de8a-4710-a90e-2a919adc00e2",
   "metadata": {
    "height": 80
   },
   "outputs": [],
   "source": [
    "agent_chain = RunnablePassthrough.assign(\n",
    "    agent_scratchpad= lambda x: format_to_openai_functions(x[\"intermediate_steps\"])\n",
    ") | prompt | model | OpenAIFunctionsAgentOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a3865c2c-cb80-4341-bcbe-3b5150749622",
   "metadata": {
    "height": 63
   },
   "outputs": [],
   "source": [
    "from langchain.memory import ConversationBufferMemory\n",
    "memory = ConversationBufferMemory(return_messages=True,memory_key=\"chat_history\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40b036fc-446f-4075-9a92-9a4bac6ecb2b",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "agent_executor = AgentExecutor(agent=agent_chain, tools=tools, verbose=True, memory=memory)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37f70acf-57ff-4ab9-a942-f0ad6e680c40",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "agent_executor.invoke({\"input\": \"my name is bob\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1554b0c-8c72-4d8d-bbed-20afd94828c5",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "agent_executor.invoke({\"input\": \"whats my name\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40887f61-6746-4e51-852d-5ff0457384b7",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "agent_executor.invoke({\"input\": \"whats the weather in sf?\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34b0b511-21d6-4c7e-b4e2-f886bc296997",
   "metadata": {},
   "source": [
    "### Create a chatbot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b1cd4bd2-703e-4e4e-8f5c-ae3d491a41f6",
   "metadata": {
    "height": 114
   },
   "outputs": [],
   "source": [
    "@tool\n",
    "def create_your_own(query: str) -> str:\n",
    "    \"\"\"This function can do whatever you would like once you fill it in \"\"\"\n",
    "    print(type(query))\n",
    "    return query[::-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67cb6fdc-ff55-4a7b-8a39-1871006aa990",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "tools = [get_current_temperature, search_wikipedia, create_your_own]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "66a73e69-acfb-471e-b54d-8ac586235521",
   "metadata": {
    "height": 709
   },
   "outputs": [],
   "source": [
    "import panel as pn  # GUI\n",
    "pn.extension()\n",
    "import panel as pn\n",
    "import param\n",
    "\n",
    "class cbfs(param.Parameterized):\n",
    "    \n",
    "    def __init__(self, tools, **params):\n",
    "        super(cbfs, self).__init__( **params)\n",
    "        self.panels = []\n",
    "        self.functions = [format_tool_to_openai_function(f) for f in tools]\n",
    "        self.model = ChatOpenAI(temperature=0).bind(functions=self.functions)\n",
    "        self.memory = ConversationBufferMemory(return_messages=True,memory_key=\"chat_history\")\n",
    "        self.prompt = ChatPromptTemplate.from_messages([\n",
    "            (\"system\", \"You are helpful but sassy assistant\"),\n",
    "            MessagesPlaceholder(variable_name=\"chat_history\"),\n",
    "            (\"user\", \"{input}\"),\n",
    "            MessagesPlaceholder(variable_name=\"agent_scratchpad\")\n",
    "        ])\n",
    "        self.chain = RunnablePassthrough.assign(\n",
    "            agent_scratchpad = lambda x: format_to_openai_functions(x[\"intermediate_steps\"])\n",
    "        ) | self.prompt | self.model | OpenAIFunctionsAgentOutputParser()\n",
    "        self.qa = AgentExecutor(agent=self.chain, tools=tools, verbose=False, memory=self.memory)\n",
    "    \n",
    "    def convchain(self, query):\n",
    "        if not query:\n",
    "            return\n",
    "        inp.value = ''\n",
    "        result = self.qa.invoke({\"input\": query})\n",
    "        self.answer = result['output'] \n",
    "        self.panels.extend([\n",
    "            pn.Row('User:', pn.pane.Markdown(query, width=450)),\n",
    "            pn.Row('ChatBot:', pn.pane.Markdown(self.answer, width=450, styles={'background-color': '#F6F6F6'}))\n",
    "        ])\n",
    "        return pn.WidgetBox(*self.panels, scroll=True)\n",
    "\n",
    "\n",
    "    def clr_history(self,count=0):\n",
    "        self.chat_history = []\n",
    "        return "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "080c3827-87fc-4dbe-a566-ca95b3f9068e",
   "metadata": {
    "height": 335
   },
   "outputs": [],
   "source": [
    "cb = cbfs(tools)\n",
    "\n",
    "inp = pn.widgets.TextInput( placeholder='Enter text here…')\n",
    "\n",
    "conversation = pn.bind(cb.convchain, inp) \n",
    "\n",
    "tab1 = pn.Column(\n",
    "    pn.Row(inp),\n",
    "    pn.layout.Divider(),\n",
    "    pn.panel(conversation,  loading_indicator=True, height=400),\n",
    "    pn.layout.Divider(),\n",
    ")\n",
    "\n",
    "dashboard = pn.Column(\n",
    "    pn.Row(pn.pane.Markdown('# QnA_Bot')),\n",
    "    pn.Tabs(('Conversation', tab1))\n",
    ")\n",
    "dashboard"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "41804e2f-4dc1-4763-8893-5e76ab5d8f14",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ef5fd8bc-9da5-4ca0-bfc9-c1bcf579fa05",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f09b8125-6f4c-47e9-8654-44388b08bd85",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72e1d6f9-fdc9-42eb-84be-dba81bbb63fd",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "513f302e-fcd3-424b-917a-e0e57602b93f",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d97a43ab-06dc-4b48-b279-72230ab855f8",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "526ea19e-5454-4abe-9b6f-d50c0d594151",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0ef90005-522a-4497-8247-e46fe0e33b3a",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c8ffd8a1-3611-4b98-ad00-8abfdc9400bc",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6f830c57-669f-4408-bc3d-1b7e309ca414",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e2004f20-b480-465d-b881-1776963750fc",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dcfab02a-9c9e-4e9c-adb7-b826c76adc5d",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "45cbc6dc-e1da-486f-85d9-17d1ca30edef",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0bf9aed9-9202-4a0c-96fb-15353d4ba84f",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ac1e8d1e-359f-484c-8ea0-b53c19d689ec",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39c54949-26a0-46f9-b9ab-773ea77c4574",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "354cfca3-0004-4667-9db4-c1680a32be4d",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6178195-8834-48ae-b41c-c1d893027161",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd214a68-f432-4106-aeda-289082ae049e",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "901a4e83-7792-4e4a-8fff-c30dbcaa8be1",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "070b3eed-982f-4e84-8d8d-8c2a7447a717",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7337263d-7b23-4584-a9dd-17d89e20e0c3",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ceba85f9-3741-4f37-ba74-28cc59b6acea",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a332c84-8019-4211-a61b-f30f4e35d1f7",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3da1622f-156f-4574-909d-0a276e3afe23",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b279336-c369-4b4b-8d0e-dac95590181f",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b4b5c36-fc6b-4f60-b8da-935873302630",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a173aaa1-ede3-4c38-ac46-93b9a7352850",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fa6869c6-ef60-4274-ad18-a8b2b112c205",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
